package com.wan.net.handler.protobuf;

import cn.hutool.core.util.ClassUtil;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.Parser;
import com.wan.net.core.packet.Packet;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

/**
 * 客户端消息处理
 * @param <Response>
 */
public abstract class ProtobufClientProcessor<Response extends Message> implements Processor {
    protected final Logger log = LoggerFactory.getLogger(getClass());
    private final int cmd;
    private final Parser<Response> parser;

    public ProtobufClientProcessor() {
        Class<?> responseClass =  ClassUtil.getTypeArgument(getClass(), 0);
        try {
            Method method = responseClass.getMethod("parse");
            parser = (Parser<Response>) method.invoke(null);
        } catch (Exception e) {
            log.error("load handler error-->" + responseClass);
            throw new RuntimeException(e.getMessage(), e);
        }
        // 直接在请求和类型响应类名命名上通过下划线约定协议id，例如Login_request_100请求登录cmd就是100
        String responseClassName = responseClass.getSimpleName().toLowerCase();
        final String[] splitData = responseClassName.split("_");
        try {
            cmd = Integer.parseInt(splitData[splitData.length - 1]);//消息ID
        } catch (Exception e) {
            log.error("load handler_cmd error-->" + responseClass);
            throw new RuntimeException(e.getMessage(), e);
        }
        HandlerFactory.addClientProcessor(this);
    }

    @Override
    public int getCmd() {
        return cmd;
    }

    @Override
    public void process(Channel channel, Packet packet) {
        if(packet.getMessageId() != cmd){
            return;
        }
        Response response = null;
        try {
            try {
                response = parser.parseFrom(packet.getContent());
            } catch (InvalidProtocolBufferException e) {
                log.error("协议[{}]数据反序列化异常",cmd,e);
                return;
            }
            doProcess(channel, response);
        }catch (Exception e){
            log.error("协议处理异常! channel:{},cmd:{},response:{}",channel,cmd,response);
        }
    }

    protected abstract void doProcess(Channel channel, Response response);
}
